Drought & crop water stress • NDVI & LST

VSWI – Vegetation Supply Water Index

VSWI is a vegetation water-stress index that combines greenness (NDVI) and surface temperature (LST) to indicate how well vegetation is supplied with water. Cool, green canopies indicate good water supply; hot, low-NDVI canopies indicate water stress or drought.


VSWI overview concept & use-cases

What does VSWI measure?

VSWI links the spectral information of vegetation (NDVI) with land-surface temperature derived from thermal infrared bands. Under water stress, transpiration decreases and canopy temperature rises, while NDVI may still be relatively high. VSWI captures this combined signal.

  • Monitoring crop water stress at field to regional scale.
  • Drought assessment over agricultural and natural vegetation.
  • Supporting irrigation management and water-use efficiency studies.
  • Providing a combined NDVI–LST feature for eco-hydrological modelling.

Note: several VSWI formulations exist in the literature (often related to TVDI or NDVI–LST space). The expression below is an example that normalises both NDVI and LST.

VSWI formula (example)

Normalized NDVI & LST form
NDVIn = (NDVI - NDVImin) / (NDVImax - NDVImin)
Tsn = (Ts - Tsmin) / (Tsmax - Tsmin)

VSWI = NDVIn · (1 - Tsn)

In this example, high VSWI corresponds to green, relatively cool canopies (good water supply), while low VSWI indicates hot and/or low-NDVI conditions (water stress).

You can adapt this formulation to match your reference (e.g. different normalisation schemes, or using 1 − TVDI).

Required inputs

Spectral indices & thermal data

Component Source
NDVI RED & NIR bands (e.g. from Landsat, Sentinel-2)
LST / surface temperature Thermal band (e.g. Landsat TIR) or LST product
NDVImin/max Derived from NDVI range over ROI / season
Tsmin/max Derived from LST range over ROI / season

Tip: NDVI and LST should be computed from cloud-free, atmospherically corrected imagery for consistent VSWI results.

Interpreting VSWI (example)

VSWI range Interpretation
High (close to 1) Green & cool canopy – low water stress
Medium Moderate water availability / mild stress
Low (close to 0) Hot and/or low NDVI – strong water stress / drought
Near zero or negative Bare soil, non-vegetated, or noisy pixels

Actual thresholds depend on crop type, climate and the period used to derive min/max NDVI and LST. Always calibrate with field data when possible.

Using VSWI in Google Earth Engine (example with Landsat 8/9)

  1. Compute NDVI from RED and NIR reflectance.
  2. Obtain surface temperature (Ts) from the thermal band or LST product.
  3. Derive NDVImin/max and Tsmin/max over your ROI / period.
  4. Compute normalised NDVI and Ts, then VSWI = NDVIn · (1 − Tsn).
// VSWI – Vegetation Supply Water Index example (Landsat 8/9) in Google Earth Engine
var roi = /* your geometry here */;

// Landsat 8/9 L2 collection (surface reflectance + ST_B10)
var l8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
  .filterBounds(roi)
  .filterDate('2023-04-01', '2023-09-30')
  .filter(ee.Filter.lt('CLOUD_COVER', 20));

// Scale factors from USGS documentation (example)
function scaleL8(img) {
  var optical = img.select(['SR_B.']).multiply(0.0000275).add(-0.2);
  var thermal = img.select('ST_B10').multiply(0.00341802).add(149.0); // Kelvin
  return img.addBands(optical, null, true)
            .addBands(thermal.rename('Ts'));
}

l8 = l8.map(scaleL8);

// Median composite
var img = l8.median();

// NDVI
var nir  = img.select('SR_B5');
var red  = img.select('SR_B4');
var ndvi = nir.subtract(red).divide(nir.add(red)).rename('NDVI');

// Surface temperature (Kelvin) & convert to Celsius if needed
var ts = img.select('Ts');  // or ts.subtract(273.15) for °C

// Derive min/max over ROI for NDVI and Ts
var ndviStats = ndvi.reduceRegion({
  reducer: ee.Reducer.minMax(),
  geometry: roi,
  scale: 30,
  maxPixels: 1e7
});

var tsStats = ts.reduceRegion({
  reducer: ee.Reducer.minMax(),
  geometry: roi,
  scale: 30,
  maxPixels: 1e7
});

var ndviMin = ee.Number(ndviStats.get('NDVI_min'));
var ndviMax = ee.Number(ndviStats.get('NDVI_max'));
var tsMin   = ee.Number(tsStats.get('Ts_min'));
var tsMax   = ee.Number(tsStats.get('Ts_max'));

// Normalised NDVI and Ts
var ndvi_n = ndvi.subtract(ndviMin)
  .divide(ndviMax.subtract(ndviMin).add(1e-6));

var ts_n = ts.subtract(tsMin)
  .divide(tsMax.subtract(tsMin).add(1e-6));

// VSWI = NDVI_n * (1 - Ts_n)
var vswi = ndvi_n.multiply(ee.Image(1).subtract(ts_n)).rename('VSWI');

// Visualisation
Map.centerObject(roi, 8);
Map.addLayer(vswi, {
  min: 0.0, max: 1.0,
  palette: ['#7f1d1d','#f97316','#eab308','#22c55e','#16a34a']
}, 'VSWI - Vegetation Supply Water Index');

// Optional export
Export.image.toDrive({
  image: vswi,
  description: 'VSWI_Landsat8_example',
  region: roi,
  scale: 30,
  maxPixels: 1e13
});

Important: treat this VSWI expression as a practical example. If you use a specific published VSWI / TVDI-based formula, replace the equations above with your exact definition while keeping this HTML layout.

Part of the Start4IT Remote Sensing Indices Library. More indices & ready-to-use code: www.start4it.com/rs-indices